<script setup lang="ts">
import { reactive, ref, watch } from 'vue';
import { type NodeMouseEvent, VueFlow, useVueFlow } from '@vue-flow/core';
import { Background } from '@vue-flow/background';
import { Controls } from '@vue-flow/controls';
import { MiniMap } from '@vue-flow/minimap';
import {
  // Alphabetical Naive UI imports
  NButton,
  NForm,
  NFormItem,
  NH2,
  NInput,
  NInputNumber,
  NLayout,
  NLayoutContent,
  NLayoutHeader,
  NLayoutSider,
  NSelect,
  NSpace,
  useMessage
} from 'naive-ui';

const { addNodes, addEdges, onPaneReady: initPane } = useVueFlow();

// 节点类型配置
const nodeTypes = reactive([
  { type: 'start', label: '开始节点' },
  { type: 'process', label: '处理节点' },
  { type: 'decision', label: '条件分支' },
  { type: 'end', label: '结束节点' }
]);

// 流程图数据 - 包含节点和边
interface NodeData {
  id: string;
  type: string;
  data: {
    label: string;
    processType?: string;
  };
  position: {
    x: number;
    y: number;
  };
}

const elements = ref<any[]>([]);
const selectedNode = ref<NodeData | null>(null);
const message = useMessage();

// 在现有代码中添加这些状态和方法
const undoStack = ref<any[]>([]);
const redoStack = ref<any[]>([]);

// 保存当前流程图状态
const saveFlow = () => {
  console.log('保存流程图', elements.value);
  message.success('流程图已保存');
};

// 撤销操作
const undo = () => {
  if (undoStack.value.length > 0) {
    const lastState = undoStack.value.pop();
    redoStack.value.push(JSON.parse(JSON.stringify(elements.value)));
    elements.value = lastState;
  } else {
    message.warning('没有可撤销的操作');
  }
};

// 重做操作
const redo = () => {
  if (redoStack.value.length > 0) {
    const nextState = redoStack.value.pop();
    undoStack.value.push(JSON.parse(JSON.stringify(elements.value)));
    elements.value = nextState;
  } else {
    message.warning('没有可重做的操作');
  }
};

// 删除选中节点
const deleteSelected = () => {
  if (selectedNode.value) {
    const newElements = elements.value.filter(el => el.id !== selectedNode.value?.id);
    undoStack.value.push(JSON.parse(JSON.stringify(elements.value)));
    elements.value = newElements;
    selectedNode.value = null;
    message.success('节点已删除');
  } else {
    message.warning('请先选择要删除的节点');
  }
};

// 在元素变化时记录状态（用于撤销/重做）
watch(
  elements,
  (_newVal, oldVal) => {
    if (oldVal.length > 0) {
      undoStack.value.push(JSON.parse(JSON.stringify(oldVal)));
    }
  },
  { deep: true }
);

// 生成唯一节点ID
const generateNodeId = () => `node_${Date.now()}_${Math.floor(Math.random() * 1000)}`;

// 处理拖拽开始
const handleDragStart = (event: DragEvent, node: any) => {
  const element = event.currentTarget as HTMLElement;
  const rect = element.getBoundingClientRect();

  // 计算鼠标在元素内部的相对位置（从中心点计算更自然）
  const offsetX = event.clientX - rect.left;
  const offsetY = event.clientY - rect.top;

  event.dataTransfer?.setData(
    'application/json',
    JSON.stringify({
      type: node.type,
      label: node.label,
      offset: {
        x: offsetX,
        y: offsetY,
        width: rect.width,
        height: rect.height
      }
    })
  );

  (event.target as HTMLElement).style.opacity = '0.5';
};

// 处理拖拽结束
const handleDragEnd = (event: DragEvent) => {
  (event.target as HTMLElement).style.opacity = '1';
};

// 处理节点点击
const handleNodeClick = (event: NodeMouseEvent) => {
  selectedNode.value = event.node;
};

// 初始化画布
const onPaneReady = (flowInstance: any) => {
  initPane(flowInstance);
  flowInstance.fitView();
};

// 处理选项
const processOptions = [
  { label: '普通处理', value: 'normal' },
  { label: '紧急处理', value: 'urgent' }
];

// 处理放置事件
const onDrop = (event: DragEvent) => {
  const flowContainer = document.querySelector('.vue-flow'); // 获取画布容器
  if (!flowContainer) return;

  const nodeData = JSON.parse(event.dataTransfer?.getData('application/json') || '{}');

  // 计算相对于画布容器的位置
  const containerRect = flowContainer.getBoundingClientRect();
  const mouseX = event.clientX - containerRect.left;
  const mouseY = event.clientY - containerRect.top;

  // 应用偏移量（让鼠标位置成为节点中心）
  const position = {
    x: mouseX - (nodeData.offset?.x || 0),
    y: mouseY - (nodeData.offset?.y || 0)
  };

  addNodes({
    id: generateNodeId(),
    type: nodeData.type,
    position,
    data: { label: nodeData.label },
    draggable: true,
    connectable: true,
    selectable: true
  });
};

// 处理连线创建
const onConnect = (params: any) => {
  addEdges({
    id: `edge-${params.source}-${params.target}`,
    source: params.source,
    target: params.target,
    animated: true,
    style: { stroke: '#333' }
  });
};
</script>

<template>
  <NLayout>
    <NLayoutHeader bordered class="h-16 flex items-center px-4">
      <NSpace justify="end">
        <NButton secondary @click="undo">撤销</NButton>
        <NButton secondary @click="redo">重做</NButton>
        <NButton secondary type="error" :disabled="!selectedNode" @click="deleteSelected">删除</NButton>
        <NButton type="primary" @click="saveFlow">保存</NButton>
      </NSpace>
    </NLayoutHeader>
    <NLayout has-sider>
      <!-- 左侧组件面板 -->
      <NLayoutSider bordered :width="240" content-style="padding: 16px;">
        <NH2>组件库</NH2>
        <div class="space-y-2">
          <div
            v-for="node in nodeTypes"
            :key="node.type"
            class="draggable-node cursor-move border rounded p-2 hover:bg-gray-100"
            draggable="true"
            @dragstart="e => handleDragStart(e, node)"
            @dragend="handleDragEnd"
          >
            {{ node.label }}
          </div>
        </div>
      </NLayoutSider>

      <!-- 流程图画布 -->
      <NLayoutContent>
        <VueFlow
          v-model="elements"
          class="vue-flow-container"
          :nodes-draggable="true"
          :nodes-connectable="true"
          :snap-to-grid="true"
          :grid-gap="20"
          @node-click="handleNodeClick"
          @pane-ready="onPaneReady"
          @dragover.prevent
          @drop="onDrop"
          @connect="onConnect"
        >
          <Background pattern-color="#eee" :gap="20" />
          <Controls class="flow-controls" position="top-right" />
          <MiniMap class="flow-minimap" position="bottom-right" />
        </VueFlow>
      </NLayoutContent>

      <!-- 右侧属性面板 -->
      <NLayoutSider v-if="selectedNode" bordered :width="300" content-style="padding: 16px;">
        <NH2>属性设置</NH2>
        <NForm :model="selectedNode.data" label-placement="left">
          <NFormItem label="节点名称">
            <NInput v-model:value="selectedNode.data.label" />
          </NFormItem>

          <template v-if="selectedNode.type === 'process'">
            <NFormItem label="处理类型">
              <NSelect v-model:value="selectedNode.data.processType" :options="processOptions" />
            </NFormItem>
          </template>

          <NFormItem label="X坐标">
            <NInputNumber v-model:value="selectedNode.position.x" />
          </NFormItem>
          <NFormItem label="Y坐标">
            <NInputNumber v-model:value="selectedNode.position.y" />
          </NFormItem>
        </NForm>
      </NLayoutSider>
    </NLayout>
  </NLayout>
</template>

<style>
.vue-flow__node {
  padding: 12px;
  border-radius: 4px;
  border: 2px solid #333;
  background: white;
  cursor: grab;
  transition:
    transform 0.2s,
    box-shadow 0.2s;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.vue-flow__node.dragging {
  cursor: grabbing;
  transform: scale(1.02);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

.vue-flow__node-start {
  border-color: #4caf50;
}

.vue-flow__node-process {
  border-color: #2196f3;
}

.vue-flow__node-decision {
  border-color: #ff9800;
}

.vue-flow__node-end {
  border-color: #f44336;
}

/* 确保画布容器正确填充父元素 */
/* .vue-flow {
  width: 100%;
  height: 100%;
  position: relative;
  background-color: #f8f8f8;
} */

/* 确保拖拽元素有明确的尺寸 */
.draggable-node {
  width: 120px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 拖拽元素的样式 */
.draggable-item {
  user-select: none;
  cursor: grab;
}

/* 连线样式 */
.vue-flow__edge-path {
  stroke: #333;
  stroke-width: 2;
}

/* 新增或修改的样式 */
.vue-flow-container {
  width: 100%;
  height: 100%;
  position: relative;
  background-color: #f8f8f8;
}

/* 控制按钮组样式（右上角） */
.flow-controls {
  top: 1rem !important;
  right: 1rem !important;
  transform: none !important;
}

/* 缩略图样式（右下角） */
.flow-minimap {
  bottom: 10rem !important; /* 改为底部定位 */
  right: 1rem !important; /* 右侧定位 */
  top: auto !important; /* 取消顶部定位 */
  transform: none !important;
  left: auto !important; /* 取消左侧定位 */
}

/* 确保MiniMap不会太大 */
.vue-flow__minimap {
  width: 200px;
  height: 150px;
  background-color: #f8f8f8;
  border: 1px solid #ddd;
}

/* 调整整体布局高度 */
.n-layout-content {
  height: calc(100vh - 4rem); /* 减去头部高度 */
  position: relative;
}
</style>
